package reading.service;

import org.springframework.transaction.annotation.Transactional;
import reading.common.domain.AuthToken;
import reading.common.exception.HlDbOptException;
import reading.common.exception.HlPrivilegeAuthException;
import reading.data.mapper.BaseDbMapper;
import reading.data.model.IEntity;
import reading.mybatis.Page;
import reading.mybatis.Pageable;

import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Project: haishu-news
 * Package: reading.service
 *
 * @author : txw
 * @version : v1.1
 * @since : 2018/10/15 12:39
 */
abstract public class AbstractBaseService<T extends IEntity> {
    private BaseDbMapper<T> baseDbMapper;

    /**
     * 设置接口实例
     *
     * @param baseDbMapper
     */
    public void setBaseDbMapper(BaseDbMapper<T> baseDbMapper) {
        this.baseDbMapper = baseDbMapper;
    }

    /**
     * 分页查询
     *
     * @param pageable
     * @return
     */
    public Page<T> findPage(Pageable pageable) {
        return new Page<>(pageable, baseDbMapper.findPage(pageable));
    }

    /**
     * 分页查询
     *
     * @param pageable
     * @return
     */
    public List<T> findEntityPage(Pageable pageable) {
        return baseDbMapper.findPage(pageable);
    }

    /**
     * 分页查询dto 实体
     *
     * @param pageable
     * @param <S>
     * @return
     */
    public <S> Page<S> findDtoPage(Pageable pageable) {
        return new Page<>(pageable, baseDbMapper.findDtoPage(pageable));
    }

    /**
     * 查询所有dto 实体
     *
     * @param <S>
     * @return
     */
    public <S> List<S> findDtoAll() {
        return baseDbMapper.findDtoAll();
    }

    /**
     * 通过userId 查询所有dto
     *
     * @param userId
     * @param <S>
     * @return
     */
    public <S> List<S> findDtoUserAll(Long userId) {
        return baseDbMapper.findDtoUserAll(userId);
    }

    /**
     * 分页查询dto 实体
     *
     * @param pageable
     * @param <S>
     * @return
     */
    public <S> List<S> findDtoList(Pageable pageable) {
        return baseDbMapper.findDtoPage(pageable);
    }

    /**
     * 创建实体
     *
     * @param t
     * @return
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public T create(T t) {
        t.setCreateTime(OffsetDateTime.now());
        baseDbMapper.create(t);
        return t;
    }

    /**
     * 创建  非自动 生成   id
     * @param t
     * @return
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public T createWithId(T t) {
        t.setCreateTime(OffsetDateTime.now());
        baseDbMapper.createWithId(t);
        return t;
    }
    /**
     * 创建实体
     *
     * @param t
     * @return
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public T createUser(T t) {
        AuthToken.getFromThreadLocal().ifPresent(authToken1 -> t.setCreateBy(authToken1.ownerId));
        t.setCreateTime(OffsetDateTime.now());
        baseDbMapper.create(t);
        return t;
    }

    /**
     * 创建实体
     * @param t
     * @return
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public T createUserWithId(T t) {
        AuthToken.getFromThreadLocal().ifPresent(authToken1 -> t.setCreateBy(authToken1.ownerId));
        t.setCreateTime(OffsetDateTime.now());
        baseDbMapper.createWithId(t);
        return t;
    }
    /**
     * 创建实体 权限访问
     *
     * @param t
     * @param roleId
     * @return
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public T createUserAuth(T t, Long roleId) {
        AuthToken.getFromThreadLocal().ifPresent(authToken1 -> {
            if (authToken1.roles.stream().noneMatch(roleId::equals)) {
                throw new HlPrivilegeAuthException();
            }
            t.setCreateBy(authToken1.ownerId);
        });
        t.setCreateTime(OffsetDateTime.now());
        baseDbMapper.create(t);
        return t;
    }

    /**
     * 更新实体
     *
     * @param t
     * @return
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public T update(T t) {
        t.setUpdateTime(OffsetDateTime.now());
        baseDbMapper.update(t);
        return t;
    }

    /**
     * 更新实体
     *
     * @param t
     * @return
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public T updateUser(T t) {
        AuthToken.getFromThreadLocal().ifPresent(authToken1 -> t.setUpdateBy(authToken1.ownerId));
        t.setUpdateTime(OffsetDateTime.now());
        baseDbMapper.update(t);
        return t;
    }

    /**
     * 更新实体 权限访问
     *
     * @param t
     * @param roleId
     * @return
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public T updateUserAuth(T t, Long roleId) {
        AuthToken.getFromThreadLocal().ifPresent(authToken1 -> {
            if (authToken1.roles.stream().noneMatch(roleId::equals)) {
                throw new HlPrivilegeAuthException();
            }
            t.setUpdateBy(authToken1.ownerId);
        });
        t.setUpdateTime(OffsetDateTime.now());
        baseDbMapper.update(t);
        return t;
    }

    /**
     * 批量创建实体
     *
     * @param t
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public void createBatch(List<T> t) {
        if (t != null && t.size() > 0) {
            t.forEach(tt -> tt.setCreateTime(OffsetDateTime.now()));
            baseDbMapper.createBatch(t);
        }
    }

    /**
     * 批量创建
     *
     * @param t
     */
    public void createBatchUser(List<T> t) {
        if (t != null && t.size() > 0) {
            final Long[] userId = new Long[1];
            AuthToken.getFromThreadLocal().ifPresent(authToken1 -> userId[0] = authToken1.ownerId);
            OffsetDateTime now = OffsetDateTime.now();
            t.forEach(tt -> {
                tt.setCreateTime(now);
                tt.setUpdateBy(userId[0]);
            });
            baseDbMapper.createBatch(t);
        }
    }

    /**
     * 根据id 查询
     *
     * @param id
     * @return
     */
    public T findById(Long id) {
        return baseDbMapper.findById(id);
    }

    /**
     * 根据id 查询
     *
     * @param id
     * @return
     */
    public T findByStrId(String id) {
        return baseDbMapper.findByStrId(id);
    }

    /**
     * 查询统计
     *
     * @param pageable
     * @return
     */
    public long countPage(Pageable pageable) {
        return baseDbMapper.countPage(pageable);
    }

    /**
     * 删除
     *
     * @param id
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public void deleteById(Long id) {
        baseDbMapper.deleteById(id);
    }

    /**
     * 删除
     *
     * @param id
     */
    @Transactional(rollbackFor = HlDbOptException.class)
    public void deleteByStrId(String id) {
        baseDbMapper.deleteByStrId(id);
    }

    /**
     * 查询所有
     *
     * @return
     */
    public List<Map<String, Object>> findAllMap() {
        return baseDbMapper.findAllMap();
    }

    /**
     * 分页查询
     *
     * @param pageable
     * @return
     */
    public Page<Map<String, Object>> findAllMapPage(Pageable pageable) {
        return new Page<>(pageable, baseDbMapper.findAllMapPage(pageable));
    }

    /**
     * 查询所有
     *
     * @return
     */
    public List<T> findAll() {
        return baseDbMapper.findAll();
    }

    public List<T> findAllTree() {
        List<T> list = baseDbMapper.findAll();
        if (list == null) {
            return null;
        }
        List<T> result = new ArrayList<>();
        List<T> parent = list.stream().filter(org -> org.getParentId() == null).collect(Collectors.toList());
        forList(parent, list, result);
        return result;
    }


    /**
     * 父节点，
     *
     * @param parent
     * @param list
     * @param orgTreeNodes
     */
    private void forList(List<T> parent, List<T> list, List<T> orgTreeNodes) {
        //创建根节点
        if (parent != null && parent.size() > 0) {
            for (T t : parent) {
                //递归
                t.setChildren(createChild(list, t));
                orgTreeNodes.add(t);
            }
        }
    }

    /**
     * 通过id 查询父级结构
     *
     * @param id
     * @return
     */
    public void findParentEntity(List<T> list, Long id, List<T> result) {
        List<T> parent = list.stream()
                .filter(elem -> id.equals(elem.getId()))
                .collect(Collectors.toList());
        if (parent != null && parent.size() > 0) {
            result.addAll(parent);
            parent.forEach(t -> findParentEntity(list, t.getParentId(), result));
        }

    }

    /**
     * 创建子节点
     *
     * @param orgList
     * @param org
     * @return
     */
    private List<T> createChild(List<T> orgList, T org) {
        List<T> orgTreeNodes = new ArrayList<>();
        //获得子节点
        List<T> list = orgList.stream()
                .filter(org1 -> org.getId().equals(org1.getParentId()))
                .collect(Collectors.toList());
        forList(list, orgList, orgTreeNodes);
        return orgTreeNodes;
    }
}
